﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq.Expressions;
using Ovvio.Business;

namespace Ovvio.Web.Core
{
    public abstract class BaseController<TKey, TModel, TEntity, TObjectContext> : Controller
        where TEntity : EntityObject, new() 
        where TObjectContext : ObjectContext, new()
        where TModel : BaseModel<TEntity>, new() 

    {
        protected BaseController(Func<TModel, TKey> modelPredicate, Expression<Func<TEntity, TKey>> entityPredicate)
            : this (modelPredicate, entityPredicate, string.Empty)
        { }

        protected BaseController(Func<TModel, TKey> modelPredicate, Expression<Func<TEntity, TKey>> entityPredicate, string entitySet)
            : this(
                new ModelProvider<TKey, TModel, TEntity, TObjectContext>(modelPredicate,
                new ServiceBase<TKey, TEntity, TObjectContext>(entitySet, string.Empty, entityPredicate)))
        { }

        protected BaseController(Func<TModel, TKey> modelPredicate, Expression<Func<TEntity, TKey>> entityPredicate, string entitySet, string paths)
            : this(
                new ModelProvider<TKey, TModel, TEntity, TObjectContext>(modelPredicate,
                new ServiceBase<TKey, TEntity, TObjectContext>(entitySet, paths, entityPredicate)))
        { }

        protected BaseController(Func<TModel, TKey> modelPredicate, ServiceBase<TKey, TEntity, TObjectContext> service) 
            : this ( new ModelProvider<TKey,TModel,TEntity,TObjectContext>(modelPredicate, service))
        { }

        protected BaseController(ModelProvider<TKey, TModel, TEntity, TObjectContext> modelProvider)
        {
            _modelProvider = modelProvider;
        }

        protected ModelProvider<TKey, TModel, TEntity, TObjectContext> _modelProvider;


        public virtual ActionResult Index()
        {
            return View(_modelProvider.GetList());
        }

        public virtual ActionResult Details(TKey id)
        {
            return View(_modelProvider.Get(id));
        }

        public ActionResult Create()
        {
            return View(_modelProvider.Create());
        }
     
        [HttpPost]
        public ActionResult Create(TModel model)
        {
            return Edit(model);
        }

        public virtual ActionResult Edit(TKey id)
        {
            return Details(id);
        }


        [HttpPost]
        public virtual ActionResult Edit(TModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    if (_modelProvider.Save(model))
                        return RedirectToAction("Index");
                    else
                        ModelState.AddModelError("", "No changes where made.");
                }

            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.InnerException != null ? ex.InnerException.Message : ex.Message);
            }
            return View(model);

        }

        [HttpPost]
        public virtual ActionResult Update(TModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    if (_modelProvider.Save(model))
                        return RedirectToAction("Index");
                    else
                        ModelState.AddModelError("", "No changes where made.");
                }

            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.InnerException != null ? ex.InnerException.Message : ex.Message);
            }
            return View("Index", _modelProvider.GetList());

        }


        public ActionResult Delete(TKey id)
        {
            return Details(id);
        }

    
        [HttpPost]
        public ActionResult Delete(TModel model)
        {
            try
            {

                if (_modelProvider.Delete(model))
                    return RedirectToAction("Index");
                else
                    ModelState.AddModelError("", "Record not found.");

            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex);
            }
            return View(model);
        }
    }
}
